package com.example.demo.demos.scheduled;

import com.alibaba.fastjson.JSON;
import com.example.demo.demos.domain.dto.UploadDTO;
import com.example.demo.demos.domain.vo.DataRows;
import com.example.demo.demos.entity.SendMail;
import com.example.demo.demos.entity.UploadList;
import com.example.demo.demos.repository.SendMailRepository;
import com.example.demo.demos.repository.UploadListRepository;
import com.example.demo.demos.service.EmailService;
import com.example.demo.demos.service.ExcelReader;
import com.example.demo.demos.service.UploadListService;
import com.example.demo.demos.util.ListComparator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Component
public class ScheduledTasks {

    @Autowired
    private SendMailRepository sendMailRepository;

    @Autowired
    private UploadListRepository uploadListRepository;

    @Autowired
    private EmailService emailService;

    @Autowired
    private UploadListService uploadListService;

    @Scheduled(fixedRate = 23000) // 10 秒
    public void taskInfo() {
        Page<UploadList> listPage = uploadListRepository.findByStatusEquals(1,Pageable.ofSize(100));
        List<UploadList> uploadLists = listPage.getContent();
        // 批量处理
        int threadCount = 2;
        ExecutorService executor = Executors.newFixedThreadPool(threadCount);

        int batchSize = uploadLists.size() / threadCount; // 每个线程处理的条数
        int remainder = uploadLists.size() % threadCount; // 剩余不足一个批次的条数

        for (int i = 0; i < threadCount; i++) {
            int start = i * batchSize + Math.min(i, remainder);
            int end = start + batchSize + (i < remainder ? 1 : 0);
            final List<UploadList> batch = uploadLists.subList(start, end);
            executor.submit(() -> processBatch(batch));
        }

        executor.shutdown();
        try {
            if (!executor.awaitTermination(1, TimeUnit.MINUTES)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
            Thread.currentThread().interrupt();
        }
        System.out.println("✅ Spring 定时任务执行中...");
    }

    private void processBatch(List<UploadList> batch) {
        // 比对目录下的文件是否和源文件一样，去重后比对
        batch.forEach(t->{
            this.doInfo(t);
        });
        // 这里执行你的业务逻辑
    }

    private void doInfo(UploadList uploadList) {
        Long beginTime = System.currentTimeMillis();
        try {
            LocalDateTime now = LocalDateTime.now();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            String subject = "文件上传变动信息："+ now.format(formatter);
            InputStream oldStream = new FileInputStream(uploadList.getOldFile());
            List<List<String>> oldData = ExcelReader.readExcel(oldStream);
            Map<List<String>, Integer> removedRows = new HashMap<>();

            List<List<String>> uniqueData = uploadListService.removeDuplicatesWithStream(oldData, removedRows);
            InputStream newStream = new FileInputStream(uploadList.getFileName());
            List<List<String>> newData = ExcelReader.readExcel(newStream);
            Map<List<String>, Integer> removedRowsNew = new HashMap<>();
            List<List<String>> newUniqueData = uploadListService.removeDuplicatesWithStream(newData, removedRowsNew);

            List<List<ListComparator.ComparisonResult>> compareLists = ListComparator.compareLists(uniqueData,newUniqueData);
            // 对比是否相等
            List<DataRows> dataRows = ListComparator.printComparisonResults(compareLists);
            List<DataRows> filters = dataRows.stream().filter(t->t.getMsg().equals("不相等")).collect(Collectors.toList());
            SendMail sendMail = new SendMail();
            Map<String, String> removedRowsAnd = new HashMap<>();
            List<List<String>> saveStream = uploadListService.removeDuplicatesWithStreamAnd(newData,removedRowsAnd);
            if(filters.size() > 0) {


                sendMail.setCodeTime(Integer.valueOf(String.valueOf(beginTime-System.currentTimeMillis())));
                // 去重后比对不一致就修改,发送邮件后将old文件变成bak一样
                Files.delete(Paths.get(uploadList.getOldFile()));
                Files.copy(Paths.get(uploadList.getFileName()), Paths.get(uploadList.getOldFile()), StandardCopyOption.REPLACE_EXISTING);
                String sendStatus = emailService.sendMailWithAttachment(uploadList.getEmail(), subject, subject, uploadList.getFileName());
                sendMail.setSendStatus(1);
                sendMail.setSendCount(1);
                if (!sendStatus.equals("")) {
                    // 失败需要记录下次继续发送邮件
                    sendMail.setSendStatus(0);
                    sendMail.setMsg(sendStatus);
                }
                sendMail.setMsg("邮件发送成功");
                sendMail.setUid(uploadList.getId());
                sendMail.setData(JSON.toJSONString(filters));
                sendMail.setOriginFile("");
                sendMail.setExTime(Integer.valueOf(String.valueOf(beginTime-System.currentTimeMillis())));
                File is = new File(uploadList.getFileName());
                String newReName = is.getParent()+"\\repack\\"+System.currentTimeMillis()+"_"+is.getName();
                UploadDTO reDTO = uploadListService.writeListToExcel(saveStream,newReName);
                if(reDTO.getStatus().equals(0)) {
                    throw new RuntimeException("写入excel异常");
                }
                sendMail.setOriginFile(newReName);
                sendMail.setSendStatus(1);
                sendMail.setSendCount(1);
                sendMailRepository.save(sendMail);
                sendMailRepository.flush();
                uploadList.setStatus(1);
                uploadListRepository.save(uploadList);
                uploadListRepository.flush();
            } else {
                sendMail.setCodeTime(Integer.valueOf(String.valueOf(beginTime-System.currentTimeMillis())));
                sendMail.setMsg("去重后比对一致");
                sendMail.setSendStatus(2);
                sendMail.setUid(uploadList.getId());
                sendMail.setExTime(Integer.valueOf(String.valueOf(beginTime-System.currentTimeMillis())));
                sendMail.setData(JSON.toJSONString(filters));
                File is = new File(uploadList.getFileName());
                String newReName = is.getParent()+"\\repack\\"+System.currentTimeMillis()+"_"+is.getName();
                UploadDTO reDTO = uploadListService.writeListToExcel(saveStream,newReName);
                if(reDTO.getStatus().equals(0)) {
                    throw new RuntimeException("写入excel异常");
                }
                sendMail.setOriginFile(newReName);

                uploadList.setStatus(1);
                sendMailRepository.save(sendMail);
                sendMailRepository.flush();
                uploadListRepository.save(uploadList);
                uploadListRepository.flush();
            }
        } catch (Exception e) {
            SendMail sendMail = new SendMail();
            sendMail.setMsg(e.getLocalizedMessage());
            sendMail.setUid(uploadList.getId());
            sendMail.setOriginFile("");
            sendMail.setSendStatus(0);
            sendMail.setExTime(Integer.valueOf(String.valueOf(beginTime-System.currentTimeMillis())));
            sendMail.setUid(uploadList.getId());
            sendMailRepository.save(sendMail);
            sendMailRepository.flush();
        }
    }

    @Scheduled(fixedRate = 19000) // 10 秒
    public void repeatMail() {
        Long beginTime = System.currentTimeMillis();
        Page<SendMail> mailPage = sendMailRepository.findBySendStatusEqualsOrderByIdDesc(0, Pageable.ofSize(5000));
        List<SendMail> sendMails = mailPage.getContent();
        // 开始重发
        List<Integer> ids = sendMails.stream().map(t->t.getUid()).collect(Collectors.toList());
        Page<UploadList> uploadLists = uploadListRepository.findByIdIn(ids,Pageable.ofSize(1000));
        List<UploadList> upList = uploadLists.getContent();
        sendMails.forEach(t->{
            LocalDateTime now = LocalDateTime.now();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            String subject = "文件上传变动信息："+ now.format(formatter);
            AtomicReference<UploadList> singleUp = new AtomicReference<>(new UploadList());
            upList.stream().filter(g->g.getId().equals(t.getId())).findFirst().ifPresent(p->{
                singleUp.set(p);
            });

            String sendStatus = emailService.sendMailWithAttachment(singleUp.get().getEmail(), subject, subject, singleUp.get().getFileName());
            if (!sendStatus.equals("")) {
                // 失败需要记录下次继续发送邮件
                t.setMsg(t.getMsg());
                t.setSendCount(t.getSendCount()+1);
            } else {
                t.setSendStatus(1);
            }
            t.setOriginFile("");
            t.setExTime(Integer.valueOf(String.valueOf(beginTime-System.currentTimeMillis())));
            sendMailRepository.save(t);
            sendMailRepository.flush();
        });
    }
    @Scheduled(fixedRate = 360000) // 10 秒
    public void delFiles()
    {
        Page<SendMail> sendMailPage = sendMailRepository.findBySendStatusEqualsOrderByIdDesc(2,Pageable.ofSize(2000));
        List<SendMail> sendMailList = sendMailPage.getContent();
        sendMailList.forEach(t->{
            Path source = Paths.get(t.getOriginFile());
            try {
                Files.delete(source);
            } catch (IOException e) {
                e.printStackTrace();
            }
            t.setOriginFile("");
            t.setSendStatus(3);
            sendMailRepository.save(t);
            sendMailRepository.flush();
        });
    }
}
